const readline = require('readline');
const Table = require('cli-table3');
const axios = require('axios');

// 接口基础地址
const API_BASE_URL = 'http://115.29.242.190:3000/api';
// const API_BASE_URL = 'http://127.0.0.1:3000/api';

// 彩票类型配置
const LOTTERY_TYPES = {
    ssq: {
        name: '双色球',
        front: { count: 6, min: 1, max: 33, maxCombo: 20 },
        back: { count: 1, min: 1, max: 16, maxCombo: 16 }
    },
    dlt: {
        name: '大乐透',
        front: { count: 5, min: 1, max: 35, maxCombo: 15 },
        back: { count: 2, min: 1, max: 12, maxCombo: 12 }
    }
};

// 常量定义
const PROGRESS_INTERVAL = 1000000; // 每100万次显示进度
const DEFAULT_PAGE_SIZE = 20; // 默认每页显示20条

// 初始化Readline
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

/**
 * 通用接口请求函数
 */
async function requestApi(url, method = 'post', data = null) {
    try {
        const options = {
            url: `${API_BASE_URL}${url}`,
            method,
            headers: {
                'Content-Type': 'application/json'
            },
            data
        };

        const response = await axios(options);
        return response.data;
    } catch (error) {
        console.error('接口请求失败:', error.message);
        return null;
    }
}

/**
 * 用户验证函数
 */
async function validateUser(username, password) {
    return await requestApi('/validateUser', 'post', { username, password });
}

/**
 * 生成一组算法有效的彩票号码
 * @param {string} type - 彩票类型 (ssq/dlt)
 * @returns {Object} 包含前区和后区号码的对象
 */
function generateRandomNumbers(type) {
    const config = LOTTERY_TYPES[type];
    if (!config) throw new Error('无效的彩票类型');
    // 生成前区号码
    const front = [];
    while (front.length < config.front.count) {
        const num = Math.floor(Math.random() * (config.front.max - config.front.min + 1)) + config.front.min;
        if (!front.includes(num)) front.push(num);
    }
    front.sort((a, b) => a - b);

    // 生成后区号码
    const back = [];
    while (back.length < config.back.count) {
        const num = Math.floor(Math.random() * (config.back.max - config.back.min + 1)) + config.back.min;
        if (!back.includes(num)) back.push(num);
    }
    back.sort((a, b) => a - b);

    return { front, back };
}

/**
 * 判断两组号码是否相同
 * @param {Object} a - 第一组号码
 * @param {Object} b - 第二组号码
 * @returns {boolean} 是否相同
 */
function isSameNumberSet(a, b) {
    if (a.front.length !== b.front.length || a.back.length !== b.back.length) return false;
    for (let i = 0; i < a.front.length; i++) {
        if (a.front[i] !== b.front[i]) return false;
    }
    for (let i = 0; i < a.back.length; i++) {
        if (a.back[i] !== b.back[i]) return false;
    }
    return true;
}

/**
 * 获取历史记录（支持分页）
 */
async function getHistory(type, page = 1, pageSize = DEFAULT_PAGE_SIZE) {
    const result = await requestApi('/getLotteryHistory', 'post', {
        type,
        page,
        pageSize
    });

    // 检查接口返回格式，提取数据数组
    if (result && result.code === 20000) {
        return {
            data: Array.isArray(result.data) ? result.data : [],
            total: result.total || 0,
            page,
            pageSize,
            totalPages: Math.ceil((result.total || 0) / pageSize)
        };
    }
    return {
        data: [],
        total: 0,
        page,
        pageSize,
        totalPages: 0
    };
}

/**
 * 显示历史记录表格（支持分页导航）
 */
async function showHistory(type) {
    const config = LOTTERY_TYPES[type];
    let currentPage = 1;

    // 显示指定页数据的函数
    const displayPage = async (pageNum) => {
        const history = await getHistory(type, pageNum, DEFAULT_PAGE_SIZE);

        if (history.total === 0) {
            console.log(`\n暂无${config.name}历史记录`);
            return showLotteryMenu(type);
        }

        const table = new Table({
            head: ['期号', '前区号码', '后区号码', '一等奖个数', '二等奖个数'],
            colWidths: [12, 20, 15, 15, 15],
            style: { head: ['green'] }
        });

        history.data.forEach((item) => {
            table.push([
                item.drawNumber,
                item.front.join(' '),
                item.back.join(' '),
                item.firstPrizeCount || 0,
                item.secondPrizeCount || 0
            ]);
        });

        console.log(`\n===== ${config.name}历史开奖记录 (共 ${history.total} 期，第 ${history.page}/${history.totalPages} 页) =====`);
        console.log(table.toString());

        // 显示分页导航
        console.log('\n分页导航:');
        console.log(`1. 上一页 (当前页: ${history.page})`);
        console.log(`2. 下一页 (共${history.totalPages}页)`);
        console.log(`3. 跳转到指定页`);
        console.log(`4. 返回上一级`);

        rl.question('请选择操作 (1-4)：', async (choice) => {
            switch (choice) {
                case '1':
                    if (history.page > 1) {
                        await displayPage(history.page - 1);
                    } else {
                        console.log('已经是第一页');
                        await displayPage(history.page);
                    }
                    break;
                case '2':
                    if (history.page < history.totalPages) {
                        await displayPage(history.page + 1);
                    } else {
                        console.log('已经是最后一页');
                        await displayPage(history.page);
                    }
                    break;
                case '3':
                    rl.question(`请输入页码 (1-${history.totalPages})：`, async (pageInput) => {
                        const targetPage = parseInt(pageInput);
                        if (isNaN(targetPage) || targetPage < 1 || targetPage > history.totalPages) {
                            console.log(`无效页码，请输入1-${history.totalPages}之间的数字`);
                            await displayPage(history.page);
                        } else {
                            await displayPage(targetPage);
                        }
                    });
                    break;
                case '4':
                    showLotteryMenu(type);
                    break;
                default:
                    console.log('无效选择，请输入1-4');
                    await displayPage(history.page);
            }
        });
    };

    // 显示第一页
    await displayPage(currentPage);
}

/**
 * 显示概率统计表格
 */
async function showStatistics(type) {
    const result = await requestApi('/getStatistics', 'post', { type });
    if (!result || result.code !== 20000) {
        console.log('\n获取统计数据失败');
        return;
    }

    const {
        frontCounts,
        backCounts,
        totalDraws,
        totalFrontNums,
        totalBackNums,
        config
    } = result.data;

    if (totalDraws === 0) {
        console.log(`\n暂无${config.name}数据可统计`);
        return;
    }

    // 前区统计表格
    const frontTable = new Table({
        head: [`${config.name}前区数字`, '出现次数', '出现概率'],
        colWidths: [15, 12, 12],
        style: { head: ['cyan'] }
    });
    Array.from({ length: config.frontMax }, (_, i) => i + 1)
        .sort((a, b) => frontCounts[b] - frontCounts[a])
        .slice(0, 10000)
        .forEach(num => {
            const rate = ((frontCounts[num] / totalFrontNums) * 100).toFixed(2);
            frontTable.push([num, frontCounts[num], `${rate}%`]);
        });

    // 后区统计表格
    const backTable = new Table({
        head: [`${config.name}后区数字`, '出现次数', '出现概率'],
        colWidths: [15, 12, 12],
        style: { head: ['magenta'] }
    });
    Array.from({ length: config.backMax }, (_, i) => i + 1)
        .sort((a, b) => backCounts[b] - backCounts[a])
        .forEach(num => {
            const rate = ((backCounts[num] / totalBackNums) * 100).toFixed(2);
            backTable.push([num, backCounts[num], `${rate}%`]);
        });

    console.log(`\n===== ${config.name}数字统计 (共 ${totalDraws} 期) =====`);
    console.log(`\n----- 前区统计 (共${config.frontCount}个，出现次数前10) -----`);
    console.log(frontTable.toString());
    console.log(`\n----- 后区统计 (共${config.backCount}个) -----`);
    console.log(backTable.toString());
}

/**
 * 执行单式号码匹配（本地执行，不调用接口保存）
 */
async function startMatching(type, targetNumbers, drawNumber) {
    const config = LOTTERY_TYPES[type];
    let attempts = 0;
    let matched = null;

    console.log(`\n开始${config.name}号码匹配...（每100万次显示进度）`);

    // 本地循环匹配
    while (!matched) {
        attempts++;
        const current = generateRandomNumbers(type);

        if (isSameNumberSet(targetNumbers, current)) {
            matched = current;
        } else if (attempts % PROGRESS_INTERVAL === 0) {
            console.log(`已尝试 ${attempts.toLocaleString()} 次...`);
        }
    }

    const table = new Table({
        head: ['匹配结果', '详情'],
        colWidths: [15, 30],
        style: { head: ['yellow'] }
    });
    table.push(
        ['状态', '匹配成功'],
        ['期号', drawNumber],
        ['总尝试次数', attempts.toLocaleString()],
        ['前区号码', matched.front.join(' ')],
        ['后区号码', matched.back.join(' ')],
        ['时间', new Date().toLocaleString()]
    );
    console.log(`\n===== ${config.name}匹配结果 =====`);
    console.log(table.toString());

    // 移除保存到历史的操作
    console.log(`\n算法选号记录不保存`);
    showLotteryMenu(type);
}

/**
 * 处理算法选号
 */
async function handleRandomSelection(type) {
    const config = LOTTERY_TYPES[type];
    // 调用接口生成算法号码
    const result = await requestApi('/generateRandomNumbers', 'post', { type });

    if (!result || result.code !== 20000) {
        console.log('通过算法生成号码失败:', result?.msg || '未知错误');
        return showLotteryMenu(type);
    }

    const numbers = {
        front: result.data.front,
        back: result.data.back
    };

    // 生成期号
    const drawResult = await requestApi('/generateUniqueDrawNumber', 'post', { type });
    const drawNumber = drawResult?.data?.drawNumber;

    const table = new Table({
        head: ['类型', '号码', '期号'],
        colWidths: [10, 25, 12]
    });
    table.push(
        ['前区', numbers.front.join(' '), drawNumber],
        ['后区', numbers.back.join(' '), '']
    );

    console.log(`\n===== ${config.name}算法选号结果 =====`);
    console.log(table.toString());
    startMatching(type, numbers, drawNumber);
}

/**
 * 计算组合数 C(n, k)
 */
function combination(n, k) {
    if (k < 0 || k > n) return 0;
    if (k === 0 || k === n) return 1;
    if (k === 1 || k === n - 1) return n;

    k = Math.min(k, n - k);
    let result = 1;
    for (let i = 1; i <= k; i++) {
        result = result * (n - k + i) / i;
    }
    return Math.round(result);
}

/**
 * 生成数组的所有组合
 */
function generateCombinations(arr, k) {
    const result = [];
    const combine = (start, current) => {
        if (current.length === k) {
            result.push([...current]);
            return;
        }
        for (let i = start; i < arr.length; i++) {
            current.push(arr[i]);
            combine(i + 1, current);
            current.pop();
        }
    };
    combine(0, []);
    return result;
}

/**
 * 执行复式号码匹配（本地执行）
 */
async function startCombinationMatching(type, combinations) {
    const config = LOTTERY_TYPES[type];
    let attempts = 0;
    let matchedCombination = null;
    let matchedIndex = -1;

    console.log(`\n开始${config.name}复式号码匹配...（共${combinations.length}注，每100万次显示进度）`);

    // 本地循环匹配
    while (matchedCombination === null) {
        attempts++;
        const current = generateRandomNumbers(type);

        // 检查是否匹配任何一个组合
        for (let i = 0; i < combinations.length; i++) {
            if (isSameNumberSet(combinations[i], current)) {
                matchedCombination = combinations[i];
                matchedIndex = i;
                break;
            }
        }

        if (attempts % PROGRESS_INTERVAL === 0) {
            console.log(`已尝试 ${attempts.toLocaleString()} 次...`);
        }
    }

    const drawResult = await requestApi('/generateUniqueDrawNumber', 'post', { type });
    const drawNumber = drawResult?.data?.drawNumber;

    const table = new Table({
        head: ['匹配结果', '详情'],
        colWidths: [15, 30],
        style: { head: ['yellow'] }
    });
    table.push(
        ['状态', '匹配成功'],
        ['期号', drawNumber],
        ['总尝试次数', attempts.toLocaleString()],
        ['匹配注数', `第${matchedIndex + 1}注`],
        ['前区号码', matchedCombination.front.join(' ')],
        ['后区号码', matchedCombination.back.join(' ')],
        ['时间', new Date().toLocaleString()]
    );

    console.log(`\n===== ${config.name}复式匹配结果 =====`);
    console.log(table.toString());

    // 保存复式选号结果
    await requestApi('/saveToHistory', 'post', {
        type,
        record: {
            front: matchedCombination.front,
            back: matchedCombination.back,
            attempts: attempts,
            combinationCount: combinations.length,
            combinationIndex: matchedIndex + 1,
            drawNumber: drawNumber
        }
    });
    console.log(`\n复式选号结果已保存到${config.name}历史记录`);
    showLotteryMenu(type);
}

/**
 * 处理复式选号
 */
function handleCombinationSelection(type) {
    const config = LOTTERY_TYPES[type];

    console.log(`\n${config.name}复式选号规则：`);
    console.log(`- 前区需选择${config.front.count}至${config.front.maxCombo}个号码（${config.front.min}-${config.front.max}）`);
    console.log(`- 后区需选择${config.back.count}至${config.back.maxCombo}个号码（${config.back.min}-${config.back.max}）`);

    rl.question(`请输入前区号码（空格分隔）：`, async (frontInput) => {
        const frontNumbers = frontInput.split(' ').map(Number);

        // 本地验证前区号码
        const validateFront = frontNumbers.length >= config.front.count &&
            frontNumbers.length <= config.front.maxCombo &&
            [...new Set(frontNumbers)].length === frontNumbers.length &&
            frontNumbers.every(n => Number.isInteger(n) && n >= config.front.min && n <= config.front.max);

        if (!validateFront) {
            console.log(`前区号码不合法！需${config.front.count}至${config.front.maxCombo}个不重复的${config.front.min}-${config.front.max}整数`);
            return showLotteryMenu(type);
        }
        frontNumbers.sort((a, b) => a - b);

        // 计算前区组合数
        const frontCombinationsCount = combination(frontNumbers.length, config.front.count);

        rl.question(`请输入后区号码（空格分隔）：`, async (backInput) => {
            const backNumbers = backInput.split(' ').map(Number);

            // 本地验证后区号码
            const validateBack = backNumbers.length >= config.back.count &&
                backNumbers.length <= config.back.maxCombo &&
                [...new Set(backNumbers)].length === backNumbers.length &&
                backNumbers.every(n => Number.isInteger(n) && n >= config.back.min && n <= config.back.max);

            if (!validateBack) {
                console.log(`后区号码不合法！需${config.back.count}至${config.back.maxCombo}个不重复的${config.back.min}-${config.back.max}整数`);
                return showLotteryMenu(type);
            }
            backNumbers.sort((a, b) => a - b);

            // 计算后区组合数和总注数
            const backCombinationsCount = combination(backNumbers.length, config.back.count);
            const totalCombinations = frontCombinationsCount * backCombinationsCount;

            // 本地生成所有组合
            console.log('正在生成所有组合...');
            const frontCombinations = generateCombinations(frontNumbers, config.front.count);
            const backCombinations = generateCombinations(backNumbers, config.back.count);

            // 合并前后区组合
            const allCombinations = [];
            for (const front of frontCombinations) {
                for (const back of backCombinations) {
                    allCombinations.push({ front, back });
                }
            }

            const selectionTable = new Table({
                head: ['类型', '选择号码', '组合数'],
                colWidths: [10, 30, 15]
            });
            selectionTable.push(
                ['前区', frontNumbers.join(' '), frontCombinationsCount],
                ['后区', backNumbers.join(' '), backCombinationsCount]
            );

            console.log(`\n===== ${config.name}复式选号结果 =====`);
            console.log(selectionTable.toString());
            console.log(`总注数：${totalCombinations.toLocaleString()} 注`);

            rl.question('是否显示前10注组合？(y/n)：', (show) => {
                if (show.toLowerCase() === 'y') {
                    const sampleTable = new Table({
                        head: ['序号', '前区号码', '后区号码'],
                        colWidths: [8, 20, 15]
                    });
                    const displayCount = Math.min(10, allCombinations.length);
                    for (let i = 0; i < displayCount; i++) {
                        sampleTable.push([
                            i + 1,
                            allCombinations[i].front.join(' '),
                            allCombinations[i].back.join(' ')
                        ]);
                    }
                    console.log(`\n前${displayCount}注组合：`);
                    console.log(sampleTable.toString());
                }

                rl.question('是否开始匹配所有组合？(y/n)：', (start) => {
                    if (start.toLowerCase() === 'y') {
                        startCombinationMatching(type, allCombinations);
                    } else {
                        console.log('已取消匹配');
                        showLotteryMenu(type);
                    }
                });
            });
        });
    });
}

/**
 * 处理手动输入
 */
async function handleManualInput(type) {
    const config = LOTTERY_TYPES[type];

    rl.question(`\n请输入${config.name}前区${config.front.count}个号码（${config.front.min}-${config.front.max}，空格分隔）：`, async (frontInput) => {
        const frontNumbers = frontInput.split(' ').map(Number);

        // 本地验证前区号码
        const isValidFront = frontNumbers.length === config.front.count &&
            [...new Set(frontNumbers)].length === config.front.count &&
            frontNumbers.every(n => Number.isInteger(n) && n >= config.front.min && n <= config.front.max);

        if (!isValidFront) {
            console.log(`前区号码不合法！需${config.front.count}个不重复的${config.front.min}-${config.front.max}整数`);
            return showLotteryMenu(type);
        }
        frontNumbers.sort((a, b) => a - b);

        rl.question(`请输入${config.name}后区${config.back.count}个号码（${config.back.min}-${config.back.max}，空格分隔）：`, async (backInput) => {
            const backNumbers = backInput.split(' ').map(Number);

            // 本地验证后区号码
            const isValidBack = backNumbers.length === config.back.count &&
                [...new Set(backNumbers)].length === config.back.count &&
                backNumbers.every(n => Number.isInteger(n) && n >= config.back.min && n <= config.back.max);

            if (!isValidBack) {
                console.log(`后区号码不合法！需${config.back.count}个不重复的${config.back.min}-${config.back.max}整数`);
                return showLotteryMenu(type);
            }
            backNumbers.sort((a, b) => a - b);

            const numbers = { front: frontNumbers, back: backNumbers };
            const drawResult = await requestApi('/generateUniqueDrawNumber', 'post', { type });
            const drawNumber = drawResult?.data?.drawNumber;

            const table = new Table({
                head: ['类型', '号码', '期号'],
                colWidths: [10, 25, 12]
            });
            table.push(
                ['前区', numbers.front.join(' '), drawNumber],
                ['后区', numbers.back.join(' '), '']
            );

            console.log(`\n===== ${config.name}手动输入号码 =====`);
            console.log(table.toString());
            startMatching(type, numbers, drawNumber);
        });
    });
}

/**
 * 显示彩票类型菜单
 */
function showLotteryMenu(type) {
    const config = LOTTERY_TYPES[type];

    console.log(`\n===== ${config.name}选号功能 =====`);
    console.log('1. 算法选号并匹配（单式）');
    console.log('2. 手动输入号码并匹配（单式）');
    console.log('3. 复式选号并匹配');
    console.log('4. 查看历史记录');
    console.log('5. 查看数字统计');
    console.log('6. 切换彩票类型');
    console.log('7. 退出程序');

    rl.question('请选择操作 (1-7)：', (choice) => {
        switch (choice) {
            case '1':
                handleRandomSelection(type);
                break;
            case '2':
                handleManualInput(type);
                break;
            case '3':
                handleCombinationSelection(type);
                break;
            case '4':
                showHistory(type);
                break;
            case '5':
                showStatistics(type).then(() => showLotteryMenu(type));
                break;
            case '6':
                showMainMenu();
                break;
            case '7':
                console.log('谢谢使用，再见！');
                rl.close();
                break;
            default:
                console.log('无效选择，请输入1-7');
                showLotteryMenu(type);
        }
    });
}

/**
 * 显示主菜单（选择彩票类型）
 */
function showMainMenu() {
    console.log('\n===== 彩票选号程序 =====');
    console.log('1. 双色球');
    console.log('2. 大乐透');
    console.log('3. 退出程序');

    rl.question('请选择操作 (1-3)：', (choice) => {
        switch (choice) {
            case '1':
                requestApi('/initializeHistoryData', 'post', { type: 'ssq' })
                    .then(() => showLotteryMenu('ssq'));
                break;
            case '2':
                requestApi('/initializeHistoryData', 'post', { type: 'dlt' })
                    .then(() => showLotteryMenu('dlt'));
                break;
            case '3':
                console.log('谢谢使用，再见！');
                rl.close();
                break;
            default:
                console.log('无效选择，请输入1-3');
                showMainMenu();
        }
    });
}

/**
 * 用户登录验证流程
 */
function promptUserLogin() {
    console.log("\n===== 系统登录 =====");
    rl.question('请输入账号：', (username) => {
        rl.question('请输入密码：', async (password) => {
            const result = await validateUser(username, password);
            if (result && result.code === 20000) {
                console.log('验证成功，正在进入程序...\n');
                showMainMenu();
            } else {
                console.log(`验证失败：${result?.msg || '未知错误'}\n`);
                promptUserLogin(); // 重新输入
            }
        });
    });
}

/**
 * 启动程序
 */
function start() {
    console.log('欢迎使用彩票选号程序（支持双色球和大乐透）');
     // 启动时先进行登录验证
    promptUserLogin();
}

// 启动程序
start();
